"""AI generation service."""
import time
import requests
import logging
from typing import Dict, Optional
from openai import OpenAI
from app.models.poi import POI
from app.models.weather_data import WeatherData
from app.services.fallback_service import FallbackService
from app.utils.error_handler import (
    retry_with_exponential_backoff,
    NetworkError,
    APIError
)

logger = logging.getLogger(__name__)


class AIGenerationService:
    """Service for AI-powered content generation."""
    
    def __init__(self, api_key: str, api_base: str):
        """Initialize AI generation service.
        
        Args:
            api_key: OpenAI API key
            api_base: OpenAI API base URL
        """
        self.client = OpenAI(
            api_key=api_key,
            base_url=api_base
        )
        self.max_retries = 3
        self.retry_delay = 1  # seconds
        self.fallback_service = FallbackService()
    
    def generate_poi_introduction(
        self,
        poi: POI,
        context: Dict
    ) -> str:
        """Generate POI introduction text using OpenAI with fallback.
        
        Args:
            poi: POI to introduce
            context: Context including weather, time, user preferences
            
        Returns:
            Generated introduction text
        """
        # Build prompt with POI and context information
        weather_info = ""
        if context.get('weather'):
            weather = context['weather']
            weather_info = f"当前天气：{weather.get('condition', '未知')}，温度{weather.get('temperature', '未知')}°C。"
        
        prompt = f"""请为以下景点生成一段简短的介绍（100-150字），适合在散步时语音播报：

景点名称：{poi.name}
景点类别：{poi.category}
基础描述：{poi.description}
{weather_info}

要求：
1. 语言生动有趣，适合口语化表达
2. 突出景点的历史文化特色
3. 结合当前天气氛围
4. 控制在100-150字以内"""

        # Try AI generation with retry
        last_error = None
        for attempt in range(self.max_retries):
            try:
                response = self.client.chat.completions.create(
                    model="gpt-4o-mini",
                    messages=[
                        {"role": "system", "content": "你是一个专业的旅游导游，擅长用生动有趣的语言介绍景点。"},
                        {"role": "user", "content": prompt}
                    ],
                    temperature=0.7,
                    max_tokens=300
                )
                
                introduction = response.choices[0].message.content.strip()
                if introduction:
                    logger.info(f"Successfully generated AI introduction for POI: {poi.name}")
                    return introduction
                else:
                    raise ValueError("Generated introduction is empty")
                    
            except Exception as e:
                last_error = e
                if attempt < self.max_retries - 1:
                    logger.warning(f"AI generation attempt {attempt + 1} failed: {str(e)}")
                    time.sleep(self.retry_delay * (attempt + 1))
                    continue
        
        # All retries failed, use fallback
        logger.error(f"AI generation failed after {self.max_retries} attempts: {last_error}")
        self.fallback_service.log_failure('poi_introduction', last_error, {'poi_id': poi.id, 'poi_name': poi.name})
        
        # Use template-based fallback
        return self.fallback_service.generate_poi_introduction_fallback(poi, context)
    
    def text_to_speech(
        self,
        text: str,
        voice: str = "alloy"
    ) -> bytes:
        """Convert text to speech using OpenAI TTS.
        
        Args:
            text: Text to convert
            voice: Voice to use (alloy, echo, fable, onyx, nova, shimmer)
            
        Returns:
            Audio file bytes
            
        Raises:
            Exception: If TTS conversion fails after retries
        """
        if not text or not text.strip():
            raise ValueError("Text cannot be empty")
        
        # Retry mechanism
        last_error = None
        for attempt in range(self.max_retries):
            try:
                response = self.client.audio.speech.create(
                    model="tts-1",
                    voice=voice,
                    input=text
                )
                
                # Read audio content
                audio_bytes = response.content
                if audio_bytes:
                    return audio_bytes
                else:
                    raise ValueError("Generated audio is empty")
                    
            except Exception as e:
                last_error = e
                if attempt < self.max_retries - 1:
                    time.sleep(self.retry_delay * (attempt + 1))  # Exponential backoff
                    continue
                    
        raise Exception(f"Failed to convert text to speech after {self.max_retries} attempts: {last_error}")
    
    def generate_background_music(
        self,
        poi: POI,
        weather: WeatherData,
        mood: str,
        suno_api_key: Optional[str] = None
    ) -> Dict:
        """Generate background music using Suno API with fallback.
        
        Args:
            poi: POI context
            weather: Weather context
            mood: Mood/atmosphere
            suno_api_key: Suno API key (optional)
            
        Returns:
            Dictionary with music info (url, duration, etc.) or preset music info
        """
        import requests
        
        if not suno_api_key:
            logger.warning("Suno API key not provided, using preset music")
            return self.fallback_service.get_preset_music(poi, weather, mood)
        
        # Build music generation prompt based on context
        weather_mood = self._get_weather_mood(weather)
        poi_style = self._get_poi_style(poi)
        
        prompt = f"Instrumental background music for walking, {poi_style} style, {weather_mood} atmosphere, {mood} mood"
        
        # Suno API endpoint (this is a placeholder - actual Suno API may differ)
        suno_api_url = "https://api.suno.ai/v1/generate"
        
        # Try AI generation with retry
        last_error = None
        for attempt in range(self.max_retries):
            try:
                response = requests.post(
                    suno_api_url,
                    headers={
                        "Authorization": f"Bearer {suno_api_key}",
                        "Content-Type": "application/json"
                    },
                    json={
                        "prompt": prompt,
                        "duration": 60,
                        "format": "mp3"
                    },
                    timeout=30
                )
                
                if response.status_code == 200:
                    audio_bytes = response.content
                    if audio_bytes:
                        logger.info(f"Successfully generated AI music for POI: {poi.name}")
                        return {
                            'audio_bytes': audio_bytes,
                            'generated': True,
                            'duration': 60
                        }
                    else:
                        raise ValueError("Generated music is empty")
                else:
                    raise Exception(f"Suno API returned status {response.status_code}: {response.text}")
                    
            except Exception as e:
                last_error = e
                if attempt < self.max_retries - 1:
                    logger.warning(f"Music generation attempt {attempt + 1} failed: {str(e)}")
                    time.sleep(self.retry_delay * (attempt + 1))
                    continue
        
        # All retries failed, use preset music fallback
        logger.error(f"Music generation failed after {self.max_retries} attempts: {last_error}")
        self.fallback_service.log_failure('music_generation', last_error, {'poi_id': poi.id, 'poi_name': poi.name})
        
        # Use preset music library
        preset_music = self.fallback_service.get_preset_music(poi, weather, mood)
        preset_music['generated'] = False
        return preset_music
    
    def _get_weather_mood(self, weather: WeatherData) -> str:
        """Get mood description based on weather.
        
        Args:
            weather: Weather data
            
        Returns:
            Mood description
        """
        condition = weather.condition.lower()
        
        if "晴" in condition or "sunny" in condition:
            return "bright and cheerful"
        elif "雨" in condition or "rain" in condition:
            return "gentle and contemplative"
        elif "云" in condition or "cloud" in condition:
            return "calm and peaceful"
        elif "雪" in condition or "snow" in condition:
            return "serene and quiet"
        else:
            return "relaxing and ambient"
    
    def _get_poi_style(self, poi: POI) -> str:
        """Get music style based on POI category.
        
        Args:
            poi: POI data
            
        Returns:
            Music style description
        """
        category = poi.category.lower()
        
        if "历史" in category or "historic" in category:
            return "classical and elegant"
        elif "自然" in category or "nature" in category:
            return "natural and organic"
        elif "文化" in category or "culture" in category:
            return "artistic and sophisticated"
        elif "公园" in category or "park" in category:
            return "light and uplifting"
        else:
            return "ambient and melodic"
